#include "WiFly/WiFly.h"
#include "AM2301/AM2301Sensor.h"
#include "GP2Y1010AU0F/DustSensor.h"
#include "Leb/Led.h"
#include "HTTPClient/HTTPClient.h"
#include "ElectricFan/ElectricFan.h"
#include "MG811/MG811.h"
#include "MS1100/MS1100.h"
#include "Buzzer/Buzzer.h"

// 修改代码，添加AP列表。自动选择可以连接的WiFi热点

//#define ARDUINO_LEONARDO
//#define ARDUINO_UNO
#define ARDUINO_MEGA2560

// 需要查看调试信息
#define DEBUG
#define SPECIFIC_INFO
#define DBG(message)    Serial.print(message)
#define DBGLN(message)    Serial.println(message)

/*********************************************************************************************
 WiFi连接
 **********************************************************************************************/
//#define SSID			"dlink"
//#define PASSWD			"123456879"
//#define AUTH			WIFLY_AUTH_WPA2_PSK
struct AccessPoint
{
	char ssid[16];
	char password[20];
	int auth;
};

//
// 可以使用的列表
//
AccessPoint APList[] =
{
{ "ChrisWiFi", "19930908",
WIFLY_AUTH_WPA2_PSK },
{ "Daniel", "123456879",
WIFLY_AUTH_WPA2_PSK },
{ 0, 0, 0 } };

static void WiFiConnect(void);

#ifdef ARDUINO_UNO
SoftwareSerial uart(2, 3);
// WiFly对象实例
WiFly wifly(uart);
#endif

#ifdef ARDUINO_LEONARDO
WiFly wifly(Serial1);
#endif

#ifdef ARDUINO_MEGA2560
WiFly wifly(Serial1);
#endif

/*********************************************************************************************
 LED对象实例 蓝色灯表示上传指示灯；黄绿色等表示错误提示灯
 **********************************************************************************************/
Led ledUpload(7);
Led ledError(8);

/*********************************************************************************************
 蜂鸣器对象实例
 **********************************************************************************************/
Buzzer buz;
static const int BUZZER_PIN = 9;
//#define BUZZER_EN

/*********************************************************************************************
 空气净化器风扇设备
 **********************************************************************************************/
ElectricFan fan(5, 6);

/*********************************************************************************************
 温度、湿度传感器
 **********************************************************************************************/
static void AM2301DataUpdate(void);
static double temperature = 0.0, humidity = 0.0;
static const int AM2301_SIG_PIN = 3;
AM2301Sensor AM2301;

/*********************************************************************************************
 粉尘传感器
 **********************************************************************************************/
static void DustSensorDataUpdate(void);
static double ppmPercf = 0.0;
static const int DS_LED_PIN = 4;
static const int DS_SIG_PIN = A2;
DustSensor GP2Y1010AU0F;

/*********************************************************************************************
 CO2传感器
 **********************************************************************************************/
static void MG811SensorDataUpdate(void);
static float mg811Data = 0.0;
static const int MG811_AOUT_PIN = A0;
MG811Sensor MG811;

/*********************************************************************************************
 甲醛传感器formaldehyde
 *********************************************************************************************/
static void MS1100SensorDataUpdate(void);
static float ms1100Data = 0.0;
static const int MS1100_AOUT_PIN = A4;
MS1100Sensor MS1100;

/*********************************************************************************************
 服务器
 *********************************************************************************************/
//#define HTTP_POST "http://10.42.0.1:8000/update_data/"
//#define HTTP_GET  "http://10.42.0.1:8000/get_ac_pwr_status/"
#define HTTP_POST "http://123.57.143.91:8000/update_data/"
#define HTTP_GET "http://123.57.143.91:8000/get_ac_pwr_status/"

static void SensorValuePost(void);
static void SwitchValueGet(void);
static void ClientValuePost(const char* url, double value);
static int ClientValueGet(const char* url);

HTTPClient client;

// POST最大尝试次数
static const int POST_TRY_CNT_MAX = 2;

// GET最大尝试次数
static const int GET_TRY_CNT_MAX = 2;

/*********************************************************************************************
 函数实现
 **********************************************************************************************/
/**
 * setup，初始化函数
 */
void setup()
{
	//
	// 串口模块波特率设置
	//
	Serial.begin(115200);
#ifdef ARDUINO_UNO
	uart.begin(38400);
#endif

#ifdef ARDUINO_LEONARDO
	Serial1.begin(38400);
#endif

#ifdef ARDUINO_MEGA2560
	Serial1.begin(115200);
#endif

	delay(100);
	DBGLN("Air Cleaner Moudle");
	WiFiConnect();
	//
	// 初始化传感器模块等
	//
	ledUpload.Init();
	ledError.Init();
	GP2Y1010AU0F.Init(DS_LED_PIN, DS_SIG_PIN);
	MG811.Init(MG811_AOUT_PIN);
	MS1100.Init(MS1100_AOUT_PIN);
	buz.Init(BUZZER_PIN);
	fan.Init();
	DBGLN("Sensors initialize ... OK");
	delay(2000);
}

/**
 * loop，主循环
 */
void loop()
{
	static int count = 0;
	DBGLN("\n######################################################################");
	AM2301DataUpdate();
	DustSensorDataUpdate();
	MG811SensorDataUpdate();
	MS1100SensorDataUpdate();
	delay(500);
	SwitchValueGet();
	if (count++ >= 2)
	{
		delay(50);
		count = 0;
#ifdef BUZZER_EN
		buz.On();
#endif
		ledUpload.On();
		SensorValuePost();
		ledUpload.Off();
#ifdef BUZZER_EN
		buz.Off();
#endif
	}
	DBGLN("######################################################################");
}

/**
 * WiFiConnect，连接到热点
 */
static void WiFiConnect(void)
{
	int tryCount = 0, index = 0;
	DBGLN("\nAccess Point: ");
	while (APList[index].ssid != 0)
	{
		if (!wifly.isAssociated(APList[index].ssid))
		{
			while (!wifly.join(APList[index].ssid, APList[index].password,
					APList[index].auth))
			{
				if (tryCount++ > 1)
				{
					//
					// 尝试连接到下一个
					//
					index++;
					tryCount = 0;
				}
				Serial.print("Failed to join ");
				Serial.println(APList[index].ssid);
				Serial.println("Wait 100 ms and I'll try again.");
				delay(100);
			}

			// 保存配置信息
			//
			wifly.save();
		}
		else
		{
			break;
		}
	}

#ifdef DEBUG
	if (wifly.isAssociated(APList[index].ssid))
	{
		DBG("Successfully connect to ");DBGLN(APList[index].ssid);
	}
#endif
}

/**
 * SensorValuePost，依次传送传感器数据到服务器上
 */
static void SensorValuePost(void)
{
	// 尝试POST次数，避免陷入死循环中。
	int tryCnt = 0;
	char jString[80];
	char temp[6];
	char hum[6];
	char co2[12];
	char dust[12];
	char form[12];
#ifdef SPECIFIC_INFO
	DBG("\nTry to post data to url: ");
	DBGLN(HTTP_POST);
#else
	DBGLN("HTTP POST.");
#endif
	snprintf(jString, sizeof(jString) / sizeof(jString[0]),
			"{\"tmp\": %s, \"hum\": %s, \"dust\": %s, \"co2\": %s, \"form\": %s}\r\n",
			dtostrf(temperature, 0, 2, temp), dtostrf(humidity, 0, 2, hum),
			dtostrf(ppmPercf, 0, 1, dust), dtostrf(mg811Data, 0, 2, co2),
			dtostrf(ms1100Data, 0, 2, form));
	DBGLN(jString);

	// 准备上传到服务器
	//
	while (client.post(HTTP_POST, jString, 5000) < 0)
	{
		ledError.On();
		if ((++tryCnt) + 1 > POST_TRY_CNT_MAX)
		{
			// 此时有两种可能的情况，一种是Wi-Fi连接断开了，还有就是服务器
			// 没有正常运行

			//
			// 尝试重新连接Wi-Fi
			//
			if (!wifly.isAssociated())
			{
				DBGLN("Call WiFiConnect() function to fix problem...");
				WiFiConnect();
			}
			ledError.Off();

			return;
		}
#ifdef SPECIFIC_INFO
		DBGLN("HTTP POST failed, try again. Please wait.");
#else
		DBGLN("POST failed.");
#endif
	}
	ledError.Off();

	//
	// 执行到此步，表示上传成功
	//
#ifdef SPECIFIC_INFO
	DBG("Successfully POST ");
	DBGLN(jString);
#else
	DBGLN("Post Ok!");
#endif
	return;
}

/**
 * SwitchValueGet，获得服务器上远程开关的状态
 */
static void SwitchValueGet(void)
{
	/*DBGLN("");
	 DEBUG(ClientValueGet(MOTOR_SWITCH_STATUS));
	 DBGLN("");*/
	DBGLN("\nAir Cleaner Power: ");
	int flag = ClientValueGet(HTTP_GET);
	if (flag == 0)
	{
		DBGLN("AC POWER OFF");
		fan.PowerOff();
	}
	else if (flag == 1)
	{
		DBGLN("AC POWER ON");
		fan.PowerOn();
	}
	else
	{
		DBGLN("UNKNOWN ERROR");
		ledError.On();
		delay(100);
		ledError.Off();
		delay(100);
	}
}

/**
 * ClientValueGet，GET
 */
static int ClientValueGet(const char* url)
{
	// 尝试GET次数，避免陷入死循环中。
	int tryCnt = 0;
	//
	// 我们需要返回一个json的字符串
	//
	char get = 0;
	bool state = false;
	String jString = "";
#ifdef SPECIFIC_INFO
	DBG("\nTry to get data from url: ");
	DBGLN(url);
#else
	DBGLN("HTTP GET.");
#endif

	//
	// 准备进行GET
	//
	while (client.get(url, 5000) < 0)
	{
		ledError.On();
		if ((++tryCnt) + 1 > GET_TRY_CNT_MAX)
		{
			// 此时有两种可能的情况，一种是Wi-Fi连接断开了，还有就是服务器
			// 没有正常运行

			//
			// 尝试重新连接Wi-Fi
			//
			if (!wifly.isAssociated())
			{
				DBGLN("Call WiFiConnect() function to fix problem...");
				WiFiConnect();
			}
			ledError.Off();

			return -1;
		}
#ifdef SPECIFIC_INFO
		DBGLN("HTTP GET failed, try again, please wait.");
#else
		DBGLN("GET failed.");
#endif
	}
	ledError.Off();
	//
	// 接收返回的文本，并取出jSon串
	//
	while (wifly.receive((uint8_t*) &get, 1, 500) == 1)
	{
		//
		// 根据接受到的字符改变状态机
		//
		if (get == '{')
		{
			state = true;
		}
		else if (get == '}')
		{
			jString += '}';
			state = false;
		}

		if (state == true)
		{
			jString += get;
		}
	}

	DBGLN(jString);

	//
	// 返回解析后的字符
	//
	int index = jString.lastIndexOf('}');
	if (index < 0)
	{
		return -1;
	}
	else
	{
		char ch = jString.charAt(index - 1);
		if (isDigit(ch))
		{
			return (ch - '0');
		}
		else
		{
			return -1;
		}
	}
	return -1;
}

/**
 * AM2301DataUpdate，温湿度数据更新函数
 */
static void AM2301DataUpdate(void)
{
	DBGLN("\nAM2301 sensor: ");
	switch (AM2301.Read(AM2301_SIG_PIN))
	{
	case AM2301LIB_OK:
		//
		// 更新温度和湿度的值
		//
		temperature = AM2301.temperature;
		humidity = AM2301.humidity;
#ifdef SPECIFIC_INFO
		DBG("temperature = ");
		DBG(temperature);
		DBG(" humidity = ");
		DBGLN(humidity);
#else
		DBGLN("AM2301 Update");
#endif
		break;
	case AM2301LIB_ERR_CHECKSUM:
		DBGLN("Checksum error ...");
		break;
	case AM2301LIB_ERR_TIMEOUT:
		DBGLN("Read timeout error ...");
		break;
	case AM2301LIB_ERR_SENSOR_NOT_FOUND:
		DBGLN("AM2301 Sensor not found ...");
		break;
	default:
		DBGLN("Unknown error ...");
		break;
	}
}

/**
 * DustSensorDataUpdate，粉尘传感器数据更新函数
 */
static void DustSensorDataUpdate(void)
{
	//
	//
	//
	GP2Y1010AU0F.Sample();
	GP2Y1010AU0F.DustDataUpdate();
	ppmPercf = GP2Y1010AU0F.ppmPercf;
#ifdef SPECIFIC_INFO
	DBGLN("\nGP2Y1010 Sensor: ");
	DBG("voltage = ");
	DBGLN(GP2Y1010AU0F.voltage);
	DBG("density = ");
	DBGLN(GP2Y1010AU0F.dustDensity);
	DBG("ppmPercf = ");DBGLN(GP2Y1010AU0F.ppmPercf);
#else
	DBGLN("Dust sensor update.");
#endif
}

/**
 * MG811SensorDataUpdate，二氧化碳传感器数据更新
 */
static void MG811SensorDataUpdate(void)
{
	DBGLN("\nMG811 sensor: ");
	mg811Data = MG811.DataGet();
	DBGLN(mg811Data);
	return;
}

/**
 * MS1100SensorDataUpdate，甲醛传感器数据更新
 */
static void MS1100SensorDataUpdate(void)
{
	DBGLN("\nMS1100 sensor: ");
	ms1100Data = MS1100.DataGet();
	DBGLN(ms1100Data);
	return;
}

